﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Parsing;

namespace OpenLS.Spreadsheet
{
    class RangeTextFunction : RangeFunction
    {
        private readonly string _text;

        public RangeTextFunction(string text, Action<Cell> clearFunction,
            Action<Dimension> clearDimension,
            TernaryAction<Cell, Cell, PasteInfo> copyFunction,
            BinaryAction<Dimension, Dimension> copyRangeFunction,
            BinaryAction<Dimension, Dimension> copyRowColumnFunction, TableFunction tableFunction, TernaryAction<Range, Range, PasteInfo> rangeCopyFunction)
            : base(clearFunction, clearDimension, copyFunction, copyRangeFunction, copyRowColumnFunction, tableFunction, rangeCopyFunction)
        {
            _text = text;
        }
    }

    class RangeFunctions
    {
        public static RangeFunction ApplyValue
        {
            get
            {
                return new RangeFunction(
                    delegate(Cell cell) { cell.Value = null; },
                    null,
                    CopyValue,
                    null, null, TableFunctions.None, CopyNoRange);
            }
        }
        private static TernaryAction<Cell, Cell, PasteInfo> CopyValue
        {
            get { return CopyValueFn; }
        }
        private static void CopyValueFn(Cell source, Cell dest, PasteInfo pasteInfo)
        {
            dest.Value = source.Value;
        }



        public static RangeFunction ApplyValueAndFormulaAndStyleRecord
        {
            get
            {
                return new RangeFunction(
                    cell =>
                    {
                        cell.Value = null;
                        cell.Format = null;
                        cell.SetFormattingRecordSafe(null);
                    },
                    dim =>
                    {
                        dim.ClearStyleRecord();
                        dim.Format = null;
                    },
                    CopyValueAndFormulaAndStyleRecord,
                    (source, destination) => destination.SetStyleRecordSafe(source.FormattingRecord), CopyRowColumnNone
                    , TableFunctions.ClearAndCopyTablesAndConditionalFormatting, CopyDataValidation
                    );
            }
        }
        private static BinaryAction<Dimension, Dimension> CopyRowColumnNone
        {
            get { return delegate { }; }
        }

        private static TernaryAction<Cell, Cell, PasteInfo> CopyValueAndFormulaAndStyleRecord
        {
            get
            {
                return delegate(Cell source, Cell destination, PasteInfo info)
                {
                    destination.SetFormattingRecordSafe(source.FormattingRecord);
                    CopyValueAndFormula(source, destination, info);
                };
            }
        }


        public static RangeFunction ApplyAll
        {
            get
            {
                return new RangeTextFunction("All",
                    cell =>
                    {
                        cell.SetFormattingRecordSafe(null);
                        cell.Formula = null;
                        cell.Value = null;
                        cell.Comment = null;
                    },
                    dim => dim.ClearStyleRecord(),
                    CopyValueStyleAndComment,
                    (source, destination) => source.SetStyleRecordSafe(destination.FormattingRecord),
                    CopyRowColumnAll, TableFunctions.ClearAndCopyTablesAndConditionalFormatting, CopyDataValidation);
            }
        }

        private static void CopyDataValidation(Range source, Range destination, PasteInfo pasteInfo)
        {
            if (pasteInfo.Transpose)
            {
                Debug.WriteLine("Transpose not implemented for data validation");
                return;
            }
            CellRelativeAddress offset = destination.TopLeftCell.Address - source.Worksheet.Selection.TopLeftCell.Address;
            List<DataValidation> dataValidations =
                Enumerable.ToList(Enumerable.Where(source.Worksheet.DataValidations,
                                                   dv => Range.Intersects(source, dv.Range)));
            foreach (var dataValidation in dataValidations)
            {
                var newDataValidation = dataValidation.Projected(destination.Worksheet, offset);
                destination.Worksheet.DataValidations.Add(newDataValidation);
            }
        }

        public static RangeFunction ApplyFormats
        {
            get
            {
                return new RangeFunction(
                    cell => cell.SetFormattingRecordUnsafe(null),
                    dim => dim.ClearStyleRecord(),
                    (source, destination, pasteInfo) => destination.SetFormattingRecordSafe(source.FormattingRecord),
                    (source, destination) => destination.SetStyleRecordSafe(source.FormattingRecord), CopyRowColumnAll
                    , TableFunctions.None, CopyDataValidation
                    );
            }
        }
        public static RangeFunction ApplyValueAndFormula
        {
            get
            {
                return new RangeFunction(
                    delegate(Cell cell)
                    {
                        cell.Value = null;
                        cell.Formula = null;
                    },
                    null,
                    CopyValueAndFormula,
                    //   delegate(Cell source, Cell dest, PasteInfo pasteInfo)
                    //        {
                    //          dest.Value = source.Value;
                    //            dest.Formula = source.Formula;
                    //      },
                    null, null, TableFunctions.None, CopyNoRange);
            }
        }
        private static void CopyNoRange(Range source, Range destination, PasteInfo pasteInfo)
        {

        }

        private static TernaryAction<Cell, Cell, PasteInfo> CopyValueAndFormula
        {
            get
            {
                return delegate(Cell source, Cell destination, PasteInfo info)
                {
                    if (source.Formula != null)
                    {
                        destination.Value = source.Value;
                        var p = new ExpressionParser(destination.Worksheet, null, LocalizationMode.NonLocalized, CellReferenceMode.Dynamic);
                        Expression exp = p.Expression(source.Formula);
                        if (p.Error != null)
                            destination.Value = p.Error; //\\ forceformula
                        else
                        {
                            try
                            {
                                if (!info.Cut)
                                    exp = exp.Offset(destination.Address - source.Address);
                                if (info.Transpose)
                                    exp = exp.Transposed(destination);
                            }
                            catch (DimensionOutOfRangeException)
                            {
                                exp = new ErrorExpression(Errors.RefError);
                            }
                            destination.SetExpression(exp);
                        }
                    }
                    else
                    {
                        destination.Expression = null;
                        destination.Value = source.Value;
                    }
                };
            }
        }






        private static TernaryAction<Cell, Cell, PasteInfo> CopyValueStyleAndComment
        {
            get
            {
                return delegate(Cell source, Cell dest, PasteInfo pasteInfo)
                {
                    dest.Value = source.Value;
                    dest.SetFormattingRecordSafe(source.FormattingRecord);
                    dest.Comment = source.Comment;
                    //\\missing validation
                };
            }
        }
        private static BinaryAction<Dimension, Dimension> CopyRowColumnAll
        {
            get
            {
                return delegate(Dimension source, Dimension destination)
                {
                    if (source is Row)
                    {
                        Row rSource = (Row)source;
                        Row rDestination = (Row)destination;
                        rDestination.Height = rSource.Height;
                    }
                    else
                    {
                        Column rSource = (Column)source;
                        Column rDestination = (Column)destination;
#if DEBUG
                        Debug.WriteLine("rSource = " + rSource.Label);
                        Debug.WriteLine("rDestination = " + rDestination.Label);
                        var w = rSource.Width;
                        Debug.WriteLine("rSource.Width = " + w);
#endif
                        rDestination.Width = rSource.Width;
                    }
                };
            }
        }




    }
}